package com.you.learning.rabbitmq.javaamqp.producer;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

public class RabbitMQProducer {

    //交换机的名称
    private final static String DIRECT_EXCHANGE_NAME = "TEST_DIRECT_EXCHANGE_NAME"; //直连模式的交换机路由方式

    private final static String TOPIC_EXCHANGE_NAME = "TEST_TOPIC_EXCHANGE_NAME"; //主题模式的交换机路由方式

    private final static String FANOUT_EXCHANGE_NAME = "TEST_FANOUT_EXCHANGE_NAME"; //广播模式的交换机路由方式

    private final static String QUEUE_NAME1 = "TEST_QUEUE_NAME1";

    private final static String QUEUE_NAME2 = "TEST_QUEUE_NAME2";

    private final static String QUEUE_NAME3 = "TEST_QUEUE_NAME3";

    private final static String DIRECT_ROUTE_KEY = "DIRECT_ROUTE_KEY";
    private final static String TOPIC_ROUTE_KEY = "TOPIC_ROUTE_KEY";
    private final static String FANOUT_ROUTE_KEY = "FANOUT_ROUTE_KEY";

    public static void main(String[] args) throws IOException, TimeoutException {

        String exchangeName = TOPIC_EXCHANGE_NAME;
        String routeKey = TOPIC_ROUTE_KEY;

        // 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 设置连接的broker(rabbitmq服务器)地址和IP
        connectionFactory.setHost("192.168.56.101");
        connectionFactory.setPort(5672);
        //设置虚拟机
        connectionFactory.setVirtualHost("/");
        //用户密码在安装rabbitmq的时候创建的
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("admin");
        // 建立连接
        Connection connection = connectionFactory.newConnection();
        //创建消息通道，之后所有的操作都是在通道上完成
        Channel channel = connection.createChannel();
        //创建一个交换机
        /**
         * exchange :交换机的名称
         * type : 交换器的类型，常见的有direct,fanout,topic等
         * durable :设置是否持久化。durable设置为true时表示持久化，反之非持久化.持久化可以将交换器存入磁盘，在服务器重启的时候不会丢失相关信息。
         * autoDelete：设置是否自动删除。autoDelete设置为true时，则表示自动删除。自动删除的前提是至少有一个队列或者交换器与这个交换器绑定，之后，所有与这个交换器绑定的队列或者交换器都与此解绑。不能错误的理解—当与此交换器连接的客户端都断开连接时，RabbitMq会自动删除本交换器
         * internal：设置是否内置的。如果设置为true，则表示是内置的交换器，客户端程序无法直接发送消息到这个交换器中，只能通过交换器路由到交换器这种方式。
         * arguments:其它一些结构化的参数，比如：alternate-exchange
         */
        channel.exchangeDeclare(exchangeName, getRouteType(exchangeName), true, false, false, null);
        /**
         * 创建队列
         *
         * queue 队列名称
         * durable 是否申明持久队列，true：rabbitmq重启后继续存在
         * exclusive 是否独占，true：只有该连接能访问
         * autoDelete 是否自动删除，true：服务器不再使用时，将自动删除该队列
         * arguments 队列其它参数
         *      x-message-ttl 队列中消息的存活时间，单位毫秒
         *      x-expires 队列在多久没有消费者访问以后会被删除
         *      x-max-length 队列的最大消息数
         *      x-max-length-bytes 队列的最大容量，单位 Byte
         *      x-dead-letter-exchange 队列的死信交换机
         *      x-dead-letter-routing-key 死信交换机的路由键
         *      x-max-priority 队列中消息的最大优先级，消息的优先级不能超过它
         */
        Map<String, Object> arguments = new HashMap<>();
        arguments.put("x-message-ttl", 10000); // 消息在10秒后没有消费，则过期失效
        // 指定死信交换机和私信队列
        String dlxChange = exchangeName + "_DLX";
        String dlxChangeType = "topic";
        String dlxQueueName = "TEST_QUEUE" + "_DLX";
        String dlxRouteKey = "#";
        channel.exchangeDeclare(dlxChange, dlxChangeType, true, false, false, null);
        channel.queueDeclare(dlxQueueName, true, false, false, null);
        channel.queueBind(dlxQueueName, dlxChange, dlxRouteKey);
        arguments.put("x-dead-letter-exchange", dlxChange);
        // 创建队列1
        channel.queueDeclare(QUEUE_NAME1, true, false, false, arguments);
        // 创建队列2
        channel.queueDeclare(QUEUE_NAME2, true, false, false, null);
        // 创建队列3
        channel.queueDeclare(QUEUE_NAME3, true, false, false, null);

        /**
         * queue: 队列名
         * exchange: 交换器名称
         * routingKey :路由key或者绑定key
         * arguments: 一些参数
         */
        // 绑定队列1
        channel.queueBind(QUEUE_NAME1, exchangeName, routeKey + ".#", null);
        // 绑定队列2
        channel.queueBind(QUEUE_NAME2, exchangeName, routeKey + ".*", null);
        // 绑定队列3
        channel.queueBind(QUEUE_NAME3, exchangeName, "*.jvm", null);
        //发送的消息内容
        String msg = "This is my first rabbit msg of " + exchangeName;
        /**
         * String exchange 不写，
         *  默认是AMQP default，
         *      The default exchange is implicitly bound to every queue,
         *      with a routing key equal to the queue name
         * String routingKey,
         * BasicProperties props,
         * byte[] body
         */
        //设置单条消息的过期时间
        AMQP.BasicProperties properties = null;
        properties = new AMQP.BasicProperties().builder().expiration("5000").build();
        channel.basicPublish(exchangeName, routeKey + ".test.jvm", properties, msg.getBytes());
        //关闭通道和连接
        channel.close();
        connection.close();
        System.out.println("--------------end-----------");
    }

    public static String getRouteType(String EXCHANGE_NAME) {
        switch (EXCHANGE_NAME) {
            case DIRECT_EXCHANGE_NAME:
                return "direct";
            case TOPIC_EXCHANGE_NAME:
                return "topic";
            case FANOUT_EXCHANGE_NAME:
                return "fanout";
            default:
                return "direct";
        }
    }
}
